﻿using Abp.Application.Services.Dto;
using Abp.Auditing;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.UI;
using FutureApp.Shop.Dto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace FutureApp.Shop
{
    /// <AppService/>
    [DisableAuditing]
    public class GoodsPropertyAppService : FutureAppAppServiceBase, IGoodsPropertyAppService
    {
        private IRepository<GoodsProperty, Guid> GoodsPropertyRepository { get; }
        private IRepository<GoodsPropertyValue, Guid> GoodsPropertyValueRepository { get; }
        private IRepository<GoodsCategoryAssemble, Guid> GoodsCategoryAssembleRepository { get; }

        /// <constructor/>
        public GoodsPropertyAppService(
            IRepository<GoodsProperty, Guid> goodsPropertyRepository,
            IRepository<GoodsPropertyValue, Guid> goodsPropertyValueRepository,
            IRepository<GoodsCategoryAssemble, Guid> goodsCategoryAssembleRepository
        )
        {
            this.GoodsPropertyRepository = goodsPropertyRepository;
            this.GoodsPropertyValueRepository = goodsPropertyValueRepository;
            this.GoodsCategoryAssembleRepository = goodsCategoryAssembleRepository;
        }

        /// <inheritDoc/>
        public async Task<ListResultDto<GoodsPropertyEntityDto>> GetGoodsPropertyList()
        {
            var list = await this.GoodsPropertyRepository.GetAllListAsync();
            return new ListResultDto<GoodsPropertyEntityDto>(
                list.MapTo<List<GoodsPropertyEntityDto>>()
                );
        }

        /// <inheritDoc/>
        public async Task<GoodsPropertyEntityDto> GetGoodsProperty(Guid id)
        {
            if (!await this.ExistGoodsProperty(id))
                throw new UserFriendlyException(L("NotExistedGoodsProperty"));
            var entity = await this.GoodsPropertyRepository.GetAsync(id);
            return entity.MapTo<GoodsPropertyEntityDto>();
        }

        /// <inheritDoc/>
        public async Task<GoodsPropertyEntityDto> GetGoodsProperty(string name)
        {
            if (!await this.ExistGoodsProperty(name))
                throw new UserFriendlyException(L("NotExistedGoodsProperty"));
            var entity = await this.GoodsPropertyRepository.FirstOrDefaultAsync(e => e.Name == name);
            return entity.MapTo<GoodsPropertyEntityDto>();
        }

        /// <inheritDoc/>
        public async Task<bool> ExistGoodsProperty(Guid id)
        {
            var count = await this.GoodsPropertyRepository.CountAsync(e => e.Id == id);
            return count != 0;
        }

        /// <inheritDoc/>
        public async Task<bool> ExistGoodsProperty(string name)
        {
            var count = await this.GoodsPropertyRepository.CountAsync(e => e.Name == name);
            return count != 0;
        }

        /// <inheritDoc/>
        public async Task CreateGoodsProperty(CreateGoodsPropertyInput input)
        {
            if (await this.ExistGoodsProperty(input.Name))
                throw new UserFriendlyException(L("ExistedGoodsPropertyName"));

            var entity = input.MapTo<GoodsProperty>();
            entity = await this.GoodsPropertyRepository.InsertAsync(entity);
            input.ValueCollection?.Select(val => new GoodsPropertyValue { PropertyId = entity.Id, Value = val })
                .ToList().ForEach(e => this.GoodsPropertyValueRepository.InsertAsync(e));
        }

        /// <inheritDoc/>
        public async Task DefineGoodsPropertyValue(DefineGoodsPropertyValueInput input)
        {
            if (!await this.ExistGoodsProperty(input.GoodsProperty))
                throw new UserFriendlyException(L("NotExistedGoodsProperty"));
            input.ValueCollection?.Select(val => new GoodsPropertyValue { PropertyId = input.GoodsProperty, Value = val })
                .ToList().ForEach(e => this.GoodsPropertyValueRepository.InsertAsync(e));
        }

        /// <inheritDoc/>
        public async Task DeleteGoodsProperty(Guid id)
        {
            if (!await this.ExistGoodsProperty(id))
                throw new UserFriendlyException(L("NotExistedGoodsProperty"));
            if (this.GoodsCategoryAssembleRepository.Count(e => e.PropertyId == id) != 0)
                throw new UserFriendlyException(L("CannotDeleteUsedGoodsProperty"));
            await this.GoodsPropertyValueRepository.DeleteAsync(e => e.PropertyId == id);
            await this.GoodsPropertyRepository.DeleteAsync(id);
        }
    }
}
